/**
 * 命令模式：
 *     以命令的形式包裹在对象中，并传给调用对象。
 *     调用对象寻找可以处理该命令的合适对象，并把该命令传递给相应的对象，该对象执行命令。
 * 
 * 生活小例子：
 *    客户下单，订单记录酷虎购买的产品，仓库根据订单给客户备货。
 * 
 * 命令模式的特点：
 *    命令模式由三种角色构成：
 *    1、发布者 invoker (发布命令，调用命令对象，不知道该如何执行与谁执行)
 *    2、接收者 receiver (提供对应接口处理请求，不知道是谁发起请求。)
 *    3、命令对象 command (接受命令，接受调用者对应接口处理发布者的请求)
 * 
 * 
 *    发布者 invoker 和 接收者 receiver各自独立， 将请求封装成命令对象 command,
 *    请求执行具体由命令对象 command 调用接收者 receiver 对应接口执行。
 * 
 *    命令对象 command 充当 发布者 invoker 与 接收者receiver 之间的链接桥梁（中间对象介入）。
 *    实现发布者与接收之间的解耦，对比过程化请求调用， 命令command 对象 拥有更长的生命周期
 *    接收者 receiver 属性方法被封装在命令对象 command 属性中，使得程序执行时可任意时刻调用接收者对象。
 * 
 *    因此command 可对请求进行进一步管控处理， 如 实现延时， 预定、排队、撤销功能。
 */

class Receiver { 
    execute() { 
        console.log("接收者执行请求")
    }
}

class Command { 
    constructor(receiver) { 
        this.receiver = receiver
    }

    execute() { 
        console.log('命令对象-> 接收者 -> 对应接口执行')
        this.receiver.execute()
    }
}

class Invoker { 
    constructor(command) { 
        this.command = command
    }
    invoke() { 
        console.log('发布者发布请求')
        this.command.execute()
    }
}

const warehouse = new Receiver()
const order = new Command(warehouse)
const client = new Invoker(order)

// client.invoke()
/**
 * 输出：
 * 发布者发布请求
   命令对象-> 接收者 -> 对应接口执行
   接收者执行请求
 */

/**
 * 应用场景“
 *    有时候需要发送某些对象请求，但是并不知道请求的接受者是谁，也不知道被请求的操作是什么。
 *    需要一种松耦合的方式来设计程序，使得发送者和接收者能够消除彼此之间的耦合关系。
 *    1、不关注执行者，不关注执行过程。
 *    2、只要结果，支持撤销请求、延后请求、延后处理、日志记录等
 * 
 * 
 * 优点：
 *    1、发布者与接收者之间实现解耦。
 *    2、可扩展命令，对请求可进行排队或日志记录。（支持撤销，队列，宏命令等功能）
 * 缺点：
 *    额外增加命令对象，非直接调用，存在一定开销。
 */

/**
 * 宏命令：
 *    一组命令集合（命令模式与组合模式的产物）
 *    发布者发布一个请求，命令对象会便利==遍历命令集合下的一系列子命令并执行，完成多任务。
 */

class MacroCommand {
    constructor() {
        this.commandList = []
    }

    add(command) {
        this.commandList.push(command)
    }
    execute() { 
        for (const command of this.commandList) {
            command.execute()
        }
    }
}

/**
 * openWeChat 是智能命令对象， 并没有传入接收对象recevier
 */
const openWeChat = {
    execute: () => { //命令对象直接处理请求
        console.log("打开微信")
    }
}

const openChrome = {
    execute() { 
        console.log("打开chrome")
    }
}

const openEmail = {
    execute() { 
        console.log("打开邮箱email")
    }
}

const macroCommand = new MacroCommand()

macroCommand.add(openWeChat)
macroCommand.add(openChrome)
macroCommand.add(openEmail)

//macroCommand.execute() //执行宏命令

/**
 * 傻瓜命令与智能命令
 * 
 *  傻瓜命令： 命令对象需要接收者来执行客户的需求。
 *  智能命令： 命令对象直接实现请求，不需要接收者，“聪明”的命令对象。
 * 
 *  “傻瓜命令”和“智能命令”区别在于：是否拥有“接收者”对象。
 * 
 *  没有“接收者”的智能命令与策略模式很类似。代码实现类似，区别在于实现目标不同
 * 
 *   1、策略模式中实现目标是一致的，只是实现算法不同（如目标：根据KPI计算奖金）
 *   2、只能命令的解决问题更广，目标更具散发性。（如目标：计算奖金/计算出勤率等）
 */